// ~ CopyRight © 2012 USTC SINOVATE  SOFTWARE CO.LTD All Rights Reserved.
package com.cmcc.zysoft.infocollection.aop;

import java.util.Date;
import java.util.Hashtable;
import java.util.Map;
import javax.annotation.Resource;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.cmcc.zysoft.framework.common.support.ResponseData;
import com.cmcc.zysoft.infocollection.model.LoginOutLog;
import com.cmcc.zysoft.infocollection.model.SystemUser;
import com.cmcc.zysoft.infocollection.service.LoginOutLogPcService;
import com.cmcc.zysoft.spring.security.model.User;
import com.cmcc.zysoft.spring.security.util.SecurityContextUtil;
import com.cmcc.zysoft.sysmanage.service.SystemUserPCService;

/**
 * @author 李三来
 * <br />邮箱： li.sanlai@ustcinfo.com
 * <br />描述：登录日志AOP
 * <br />版本:1.0.0
 * <br />日期： 2013-2-5 上午9:22:50
 * <br />CopyRight © 2012 USTC SINOVATE  SOFTWARE CO.LTD All Rights Reserved.
 */
@Component
@Aspect
public class LoginLogAspect {

    /**
     * 终端类型：电脑.
     */
    private static final String CLIENT_TYPE_PC = "1";

    /**
     * 终端类型：手机.
     */
    private static final String CLIENT_TYPE_MOBILE = "2";

    /**
     * 操作类型：登录.
     */
    private static final String OPERATE_TYPE_LOGIN = "1";

    /**
     * 操作类型：注销.
     */
    //private static final String OPERATE_TYPE_LOGOUT = "2";

    /**
     * 登录成功.
     */
    private static final String LOGIN_SUCCESS = "1";

    /**
     * 登录失败.
     */
    private static final String LOGIN_FAIL = "0";
    
    /**
     * 属性名称：用户名不存在.
     * 类型：String
     */
    public static final String USERNAME_NOT_FOUND = "UsernameNotFound";
    
    /**
     * 属性名称：用户未注册.
     */
    public static final String USER_NOT_REGISTER = "UserNotRegister";
    
    /**
     * 用户名或者密码错误.
     */
//    private static final String BAD_CREDENTIALS = "BadCredentials";
    
    /**
     * 验证码错误.
     */
    public static final String BAD_CAPATCH = "BadCapatch";
    
    @Resource
	private SystemUserPCService systemUserPCService;
    
    /**
     * 属性名称：logger.
     * 类型：Logger.
     */
    private static final Logger logger = LoggerFactory.getLogger(LoginLogAspect.class);
    
    /**
     * 存放登录开始时间.
     */
    public static Hashtable<String, Object> TIME_COMSUME_MAP = new Hashtable<String, Object>();
    
    /**
     * 属性名称：loginOutLogPcService.
     * 类       型：LoginOutLogPcService.
     */
    @Resource
    private LoginOutLogPcService loginOutLogPcService;

    /**
     * 手机侧登录日志切点.
     * 返回类型：void
     */
    @Pointcut("execution(* com.cmcc.zysoft.infocollection.mobile.controller.MLoginController.login(..))")
    public void mobileLoginPointcut() {}

    /**
     * PC侧登录成功日志切点.
     * 返回类型：void
     */
    @Pointcut("execution(* com.cmcc.zysoft.spring.security.controller.SecurityController.loginSuccess(..))")
    public void pcLoginSuccessPointcut() {}
    
    /**
     * PC侧登录失败日志切点.
     * 返回类型：void
     */
    @Pointcut("execution(* com.cmcc.zysoft.spring.security.controller.SecurityController.loginFailure(..))")
    public void pcLoginFailPointcut() {}
    
    /**
     * 手机侧登录日志.
     * @param map 
     * 返回类型：void
     */
    @AfterReturning(pointcut="mobileLoginPointcut()", 
            argNames="map", 
            returning="map")
    @Transactional
    public void writeMobileLoginLog(Map<String, Object> map) {
        logger.debug("#记录手机侧登录日志");
        //获取手机侧登录名
        String userName = (String)map.get("userName");
		SystemUser list = this.systemUserPCService.getUserByuserName(userName);
		boolean success = (Boolean)map.get("success");
		LoginOutLog log = new LoginOutLog();
		//计算登录耗时，取出方法执行前的时间戳
		long startTime = (Long)TIME_COMSUME_MAP.get(userName);
		TIME_COMSUME_MAP.remove(userName);
		log.setTimeConsuming(System.currentTimeMillis() - startTime);
		log.setClientType(CLIENT_TYPE_MOBILE);
		log.setUserName(userName);
		log.setOperateType(OPERATE_TYPE_LOGIN);
		log.setLoginIp(map.get("loginIp").toString());
		log.setOperateTime(new Date());
		if(null != list) {
			String userId = list.getUserId();
			String userCompanyId = list.getCompanyId();
			log.setUserId(userId);
			log.setCompanyId(userCompanyId);
		}
        if(success) {
            logger.debug("#用户：" + userName + " 手机登录系统成功");
            log.setLogContent("用户：" + userName + " 手机登录系统成功");
            log.setLoginResult(LOGIN_SUCCESS);
        } else {
			String logContent = "用户： " + userName;
            String type = map.get("type").toString();
            switch (type) {
            case USERNAME_NOT_FOUND:
                logContent += " 登录失败,用户不存在或已删除";
                break;
            case BAD_CAPATCH:
                logContent += " 登录失败,验证码错误";
                break;
            case USER_NOT_REGISTER : 
            	logContent += " 登录失败,用户未注册";
                break;
            default:
                logContent += " 登录失败,用户名或者密码错误";
                break;
            }
            log.setLogContent(logContent);
            log.setLoginResult(LOGIN_FAIL);
            logger.debug("#" + logContent);
		}
		//持久化
		this.loginOutLogPcService.saveLog(log);
    }
    
    /**
     * PC侧登录成功日志.
     * @param responseData
     * 返回类型：void
     */
    @AfterReturning(pointcut="pcLoginSuccessPointcut()", 
            argNames="responseData", 
            returning="responseData")
    @Transactional
    public void writePCLoginSuccessLog(ResponseData responseData) {
        logger.debug("#记录PC侧登录日志");
        User user = SecurityContextUtil.getCurrentUser();
        String userName = user.getUsername();
        LoginOutLog log = new LoginOutLog();
        //计算登录耗时，取出方法执行前的时间戳
        long startTime = (Long)TIME_COMSUME_MAP.get(userName);
        TIME_COMSUME_MAP.remove(userName);
        log.setTimeConsuming(System.currentTimeMillis() - startTime);
        
        log.setClientType(CLIENT_TYPE_PC);
        log.setCompanyId(user.getCompanyId());
        log.setLoginIp(user.getLoginIp());
        log.setOperateTime(new Date());
        log.setUserName(user.getUsername());
        log.setUserId(user.getUserId());
        log.setOperateType(OPERATE_TYPE_LOGIN);
        boolean isSuccess = responseData.isSuccess();
        //判断用户是否登录成功
        if(isSuccess) {
            logger.debug("#用户："+user.getRealName() + " 登录系统成功");
            log.setLogContent("用户：" + user.getRealName() + " 登录系统成功");
            log.setLoginResult(LOGIN_SUCCESS);
        }else{
            logger.debug("#用户：" + user.getRealName() + " 登录系统失败，登录地址不正确！");
            log.setLogContent("用户：" + user.getRealName() + " 登录系统失败，登录地址不正确！");
            log.setLoginResult(LOGIN_FAIL);
        }
        //持久化
        this.loginOutLogPcService.saveLog(log);
    }
    
    /**
     * PC侧登录失败日志.
     * @param responseData
     * 返回类型：void
     */
    @AfterReturning(pointcut="pcLoginFailPointcut()", 
            argNames="responseData", 
            returning="responseData")
    @Transactional
    public void writePCLoginFailLog(ResponseData responseData) {
        logger.debug("#记录PC侧登录失败日志");
        //登录失败的类型
        String type = responseData.getType();
        //登录的用户名信息
        Object userNameObj = responseData.getMessage();
        String userName = userNameObj != null? (String)userNameObj : null;
        String loginIp = responseData.getRequestURI();
        LoginOutLog log = new LoginOutLog();
        //计算登录耗时，取出方法执行前的时间戳
        long startTime = (Long)TIME_COMSUME_MAP.get(userName);
        TIME_COMSUME_MAP.remove(userName);
        log.setTimeConsuming(System.currentTimeMillis() - startTime);
        log.setLoginResult(LOGIN_FAIL);
        log.setClientType(CLIENT_TYPE_PC);
        log.setOperateTime(new Date());
        log.setUserName(userName);
        log.setLoginIp(loginIp);
        log.setOperateType(OPERATE_TYPE_LOGIN);
        String logContent = "用户： " + userName;
        switch (type) {
	        case USERNAME_NOT_FOUND:
	            logContent += " 登录失败,用户名不存在";
	            break;
	        case BAD_CAPATCH:
	            logContent += " 登录失败,验证码错误";
	            break;
	        case "NoAuthority":
	            logContent += " 登录失败,信息采集员无此权限";
	            break;
	        default:
	            logContent += " 登录失败,用户名或者密码错误";
	            break;
        }
        log.setLogContent(logContent);
        logger.debug("#" + logContent);
        //持久化
        this.loginOutLogPcService.saveLog(log);
    }
}